#ifndef OOM_H
#define OOM_H

#include <apr_hash.h>
#include <apr_thread_cond.h>
#include <apr_thread_mutex.h>
#include "mpi.h"
#include "uid.h"

/** \file oom.h
 *  \brief This file defines the interface to the opaque object manager.
 */

typedef struct {
	int *members;
	int num_members;
	int is_permanent;
} Group;

typedef struct {
	MPI_Group group;
	int p2p_context;
	int coll_context;
	int source;
	int is_permanent;
	int topology;
	apr_hash_t *attributes;
} Comm;

typedef struct _Typemap {
	MPI_Datatype type;
	MPI_Aint disp;
	struct _Typemap *next;
} Typemap;

typedef struct {
  int num_elements; /** lb/ub not included */
  Typemap *typemap;
  Typemap *lb;
  Typemap *ub;
  MPI_Aint extent;
  int size;
  int committed;
} Datatype;

typedef enum { INACTIVE, NEW, PENDING, READY, COMPLETE } RequestStatus;

typedef enum { SEND, RECV } RequestType;

typedef struct {
	int source;
	int dest;
	int context;
	int tag;
} Envelope;

typedef struct {
	RequestType req_type;
	void *buf;
	int count;
	MPI_Datatype datatype;
	Envelope request_env;
	Envelope matched_env;
	int source_world_rank;
	int dest_world_rank;
	int status;
	apr_thread_mutex_t *mutex;
	apr_thread_cond_t *cond;
	int is_persistent;
	int num_bytes;
} Request;

typedef struct {
	MPI_User_function *function;
	int commute;
} Op;

typedef struct {
	int bogus;
} Errhandler;

typedef struct {
	MPI_Copy_function *copy_fn;
	MPI_Delete_function *delete_fn;
	void *extra_state;
} Keyval;

void OOM_init();

MPI_Group OOM_group_create(int *members, int num_members);
void OOM_group_destroy(MPI_Group handle);
Group *OOM_group_lookup(MPI_Group handle);

MPI_Comm OOM_comm_create(MPI_Group group, int p2p_context, int coll_context,
	int source);
void OOM_comm_destroy(MPI_Comm handle);
Comm *OOM_comm_lookup(MPI_Comm handle);

MPI_Datatype OOM_datatype_create();
void OOM_datatype_destroy(MPI_Datatype handle);
Datatype *OOM_datatype_lookup(MPI_Datatype handle);
Typemap *OOM_typemap_create();

MPI_Request OOM_request_create();
void OOM_request_destroy(MPI_Request handle);
Request *OOM_request_lookup(MPI_Request handle);

MPI_Op OOM_op_create_explicit(MPI_User_function *function, int commute, MPI_Op inhandle);
MPI_Op OOM_op_create(MPI_User_function *function, int commute);
void OOM_op_destroy(MPI_Op handle);
Op *OOM_op_lookup(MPI_Op handle);

MPI_Errhandler OOM_errhandler_create();
void OOM_errhandler_destroy(MPI_Errhandler handle);
Errhandler *OOM_errhandler_lookup(MPI_Errhandler handle);

uid_pool *OOM_get_context_tag_pool();

int OOM_keyval_create();
void OOM_keyval_destroy(int handle);
Keyval *OOM_keyval_lookup(int handle);

void *OOM_palloc(apr_size_t size);

void OOM_finalize();

#endif
